#!/usr/bin/env python3
"""
工具使用示例

这个示例展示了：
1. 如何单独使用各种工具
2. 工具的开发原理和结构
3. 如何创建自定义工具
4. 工具在Agent中的集成使用
"""

import sys
import os
from pathlib import Path
import json

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent
sys.path.append(str(project_root))

from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.prompt import Prompt, Confirm
from rich.syntax import Syntax

from core.tools_manager import tool_manager, ToolManager
from chains.agent_chain import tool_demo_agent
from config.settings import settings

console = Console()

def display_welcome():
    """显示欢迎信息"""
    welcome_text = """
🛠️ LangChain 工具使用示例

本示例将展示：
1. 工具的基本概念和结构
2. 如何单独使用各种工具
3. 如何开发自定义工具
4. 工具的最佳实践
5. 常见问题和解决方案

工具是LangChain中非常重要的概念，它们让AI能够：
- 访问外部数据源
- 执行计算任务
- 与外部API交互
- 处理文档和文件
    """
    
    panel = Panel(
        welcome_text.strip(),
        title="🛠️ 工具使用示例",
        border_style="blue",
        padding=(1, 2)
    )
    
    console.print(panel)
    console.print()

def show_tool_theory():
    """展示工具的理论基础"""
    console.print("[bold green]📚 工具理论基础[/bold green]\n")
    
    theory_text = """
LangChain工具的核心概念：

1. 工具接口（Tool Interface）
   - name: 工具名称，用于标识
   - description: 工具描述，帮助AI理解何时使用
   - func: 实际执行的函数

2. 工具的生命周期：
   - 注册：将工具添加到工具管理器
   - 发现：AI根据描述选择合适的工具
   - 调用：执行工具函数
   - 返回：处理工具执行结果

3. 工具的类型：
   - 搜索工具：获取外部信息
   - 计算工具：执行数学和逻辑运算
   - API工具：与外部服务交互
   - 文档工具：处理文档和文本
   - 系统工具：与操作系统交互
    """
    
    theory_panel = Panel(
        theory_text.strip(),
        title="工具理论",
        border_style="cyan",
        padding=(1, 2)
    )
    console.print(theory_panel)

def show_tool_structure():
    """展示工具的代码结构"""
    console.print("\n[bold green]🏗️ 工具代码结构[/bold green]\n")
    
    # 展示一个简单的工具示例
    tool_code = '''
from langchain.tools import Tool

def my_calculator(expression: str) -> str:
    """执行数学计算"""
    try:
        result = eval(expression, {"__builtins__": {}}, {})
        return f"计算结果: {result}"
    except Exception as e:
        return f"计算错误: {str(e)}"

# 创建工具
calculator_tool = Tool(
    name="计算器",
    description="执行基础数学计算，输入数学表达式如 '2+2'",
    func=my_calculator
)
'''
    
    syntax = Syntax(tool_code, "python", theme="monokai", line_numbers=True)
    console.print(syntax)
    
    structure_text = """
工具的三个核心要素：

1. name（名称）
   - 简洁明了的标识符
   - AI用来选择工具的关键信息

2. description（描述）
   - 详细说明工具的功能
   - 包含输入格式和使用场景
   - 这是AI选择工具的主要依据

3. func（函数）
   - 实际执行任务的Python函数
   - 通常接受字符串输入，返回字符串结果
   - 需要包含错误处理逻辑
    """
    
    structure_panel = Panel(
        structure_text.strip(),
        title="代码结构说明",
        border_style="yellow",
        padding=(1, 2)
    )
    console.print(structure_panel)

def list_available_tools():
    """列出所有可用工具"""
    console.print("\n[bold green]📋 可用工具列表[/bold green]\n")
    
    tools_info = tool_demo_agent.list_all_tools()
    
    table = Table(title="工具清单")
    table.add_column("工具名称", style="cyan", no_wrap=True)
    table.add_column("状态", style="green")
    table.add_column("描述", style="white")
    
    for tool in tools_info["tools"]:
        status = "✅ 可用" if tool["available"] else "❌ 不可用"
        table.add_row(
            tool["name"],
            status,
            tool["description"][:60] + "..." if len(tool["description"]) > 60 else tool["description"]
        )
    
    console.print(table)
    console.print(f"\n总计: {tools_info['total_count']} 个工具")

def demo_individual_tool():
    """演示单个工具的使用"""
    console.print("\n[bold green]🔍 单个工具演示[/bold green]\n")
    
    # 显示可用工具
    tool_names = tool_manager.get_tool_names()
    console.print("可用工具:", ", ".join(tool_names))
    
    while True:
        tool_name = Prompt.ask("\n请选择要演示的工具 (输入 'back' 返回)")
        
        if tool_name.lower() == 'back':
            break
            
        if tool_name not in tool_names:
            console.print(f"[red]工具 '{tool_name}' 不存在[/red]")
            continue
        
        # 获取工具演示
        demo_result = tool_demo_agent.demo_tool_usage(tool_name)
        
        if not demo_result["success"]:
            console.print(f"[red]演示失败: {demo_result['error']}[/red]")
            continue
        
        # 显示工具信息
        tool_info = demo_result["tool_info"]
        info_panel = Panel(
            f"名称: {tool_info['name']}\n描述: {tool_info['description']}\n类型: {tool_info['type']}",
            title="工具信息",
            border_style="blue"
        )
        console.print(info_panel)
        
        # 显示使用提示
        tips = demo_result["usage_tips"]
        tips_text = "\n".join([f"• {tip}" for tip in tips])
        tips_panel = Panel(
            tips_text,
            title="使用提示",
            border_style="yellow"
        )
        console.print(tips_panel)
        
        # 获取用户输入进行测试
        test_input = Prompt.ask("\n请输入测试数据 (留空跳过测试)")
        
        if test_input.strip():
            console.print("\n[dim]正在执行工具...[/dim]")
            result = tool_manager.execute_tool(tool_name, test_input)
            
            result_panel = Panel(
                result,
                title="执行结果",
                border_style="green"
            )
            console.print(result_panel)

def create_custom_tool():
    """创建自定义工具的演示"""
    console.print("\n[bold green]🛠️ 创建自定义工具[/bold green]\n")
    
    console.print("让我们创建一个自定义工具：文本长度计算器")
    
    # 展示自定义工具代码
    custom_tool_code = '''
def text_length_calculator(text: str) -> str:
    """计算文本长度的自定义工具"""
    try:
        char_count = len(text)
        word_count = len(text.split())
        line_count = len(text.split('\\n'))
        
        result = f"""
文本分析结果：
- 字符数: {char_count}
- 单词数: {word_count}
- 行数: {line_count}
        """
        return result.strip()
        
    except Exception as e:
        return f"分析错误: {str(e)}"

# 注册自定义工具
success = tool_manager.add_custom_tool(
    name="text_analyzer",
    description="分析文本长度，包括字符数、单词数和行数",
    func=text_length_calculator
)
'''
    
    syntax = Syntax(custom_tool_code, "python", theme="monokai", line_numbers=True)
    console.print(syntax)
    
    # 实际创建并注册工具
    def text_length_calculator(text: str) -> str:
        """计算文本长度的自定义工具"""
        try:
            char_count = len(text)
            word_count = len(text.split())
            line_count = len(text.split('\n'))
            
            result = f"""
文本分析结果：
- 字符数: {char_count}
- 单词数: {word_count}
- 行数: {line_count}
            """
            return result.strip()
            
        except Exception as e:
            return f"分析错误: {str(e)}"
    
    # 注册工具
    success = tool_manager.add_custom_tool(
        name="text_analyzer",
        description="分析文本长度，包括字符数、单词数和行数",
        func=text_length_calculator
    )
    
    if success:
        console.print("\n[green]✅ 自定义工具创建成功！[/green]")
        
        # 测试自定义工具
        if Confirm.ask("是否测试自定义工具？"):
            test_text = Prompt.ask("请输入要分析的文本")
            result = tool_manager.execute_tool("text_analyzer", test_text)
            
            result_panel = Panel(
                result,
                title="自定义工具执行结果",
                border_style="green"
            )
            console.print(result_panel)
    else:
        console.print("\n[red]❌ 自定义工具创建失败[/red]")

def show_best_practices():
    """展示工具开发的最佳实践"""
    console.print("\n[bold green]✨ 工具开发最佳实践[/bold green]\n")
    
    practices = [
        {
            "标题": "1. 清晰的工具描述",
            "内容": "描述应该详细说明工具的功能、输入格式和使用场景，这是AI选择工具的关键"
        },
        {
            "标题": "2. 健壮的错误处理",
            "内容": "工具函数应该包含完善的错误处理，避免因异常导致Agent执行失败"
        },
        {
            "标题": "3. 一致的输入输出格式",
            "内容": "通常使用字符串作为输入和输出，保持接口的一致性"
        },
        {
            "标题": "4. 适当的工具粒度",
            "内容": "工具不应该太复杂（难以理解）也不应该太简单（缺乏实用性）"
        },
        {
            "标题": "5. 考虑安全性",
            "内容": "对于可能执行系统命令或访问文件的工具，需要添加安全检查"
        },
        {
            "标题": "6. 提供使用示例",
            "内容": "在描述中包含使用示例，帮助AI更好地理解如何使用工具"
        }
    ]
    
    for practice in practices:
        panel = Panel(
            practice["内容"],
            title=practice["标题"],
            border_style="cyan",
            padding=(1, 2)
        )
        console.print(panel)
        console.print()

def show_common_issues():
    """展示常见问题和解决方案"""
    console.print("\n[bold green]🚨 常见问题和解决方案[/bold green]\n")
    
    issues = [
        {
            "问题": "AI选择了错误的工具",
            "原因": "工具描述不够清晰或过于相似",
            "解决方案": "优化工具描述，明确使用场景和输入格式"
        },
        {
            "问题": "工具执行失败",
            "原因": "缺乏错误处理或输入验证",
            "解决方案": "添加完善的错误处理和输入验证逻辑"
        },
        {
            "问题": "工具响应太慢",
            "原因": "工具内部逻辑复杂或网络请求超时",
            "解决方案": "优化算法，添加超时设置，考虑异步处理"
        },
        {
            "问题": "工具结果格式不一致",
            "原因": "不同工具返回格式差异太大",
            "解决方案": "制定统一的返回格式规范"
        }
    ]
    
    for issue in issues:
        content = f"原因: {issue['原因']}\n解决方案: {issue['解决方案']}"
        panel = Panel(
            content,
            title=f"❌ {issue['问题']}",
            border_style="red",
            padding=(1, 2)
        )
        console.print(panel)

def main():
    """主函数"""
    console.print("[bold cyan]🛠️ LangChain 工具使用示例[/bold cyan]\n")
    
    # 验证配置
    if not settings.validate_configuration():
        console.print("[red]配置验证失败，请检查您的设置[/red]")
        return
    
    display_welcome()
    
    # 示例菜单
    examples = [
        ("工具理论基础", show_tool_theory),
        ("工具代码结构", show_tool_structure),
        ("可用工具列表", list_available_tools),
        ("单个工具演示", demo_individual_tool),
        ("创建自定义工具", create_custom_tool),
        ("最佳实践", show_best_practices),
        ("常见问题", show_common_issues)
    ]
    
    while True:
        console.print("\n" + "="*60)
        console.print("[bold yellow]请选择要运行的示例：[/bold yellow]")
        
        for i, (name, _) in enumerate(examples, 1):
            console.print(f"{i}. {name}")
        
        console.print("0. 退出")
        
        try:
            choice = Prompt.ask("\n请输入选项", choices=[str(i) for i in range(len(examples) + 1)])
            choice = int(choice)
            
            if choice == 0:
                console.print("[cyan]再见！[/cyan]")
                break
            
            if 1 <= choice <= len(examples):
                console.print(f"\n{'='*60}")
                console.print(f"运行: {examples[choice-1][0]}")
                console.print('='*60)
                
                try:
                    examples[choice-1][1]()
                except Exception as e:
                    console.print(f"[red]示例运行失败: {str(e)}[/red]")
            else:
                console.print("[red]无效选项[/red]")
                
        except (ValueError, KeyboardInterrupt):
            console.print("\n[cyan]程序已退出[/cyan]")
            break
        except Exception as e:
            console.print(f"[red]发生错误: {str(e)}[/red]")

if __name__ == "__main__":
    main() 